[XEN] Early page fault handler to deal with spurious page faults.
authorkfraser@localhost.localdomain <kfraser@localhost.localdomain>
Thu, 7 Dec 2006 14:03:54 +0000 (14:03 +0000)
committerkfraser@localhost.localdomain <kfraser@localhost.localdomain>
Thu, 7 Dec 2006 14:03:54 +0000 (14:03 +0000)
Signed-off-by: Keir Fraser <keir@xensource.com>
xen/arch/x86/crash.c
xen/arch/x86/setup.c
xen/arch/x86/traps.c
xen/arch/x86/x86_32/domain_page.c
xen/arch/x86/x86_32/entry.S
xen/arch/x86/x86_64/entry.S
xen/include/xen/domain_page.h

index 3389174a7a4f63fd934baaa13410da9453f97102..a5b0aeedf10f4cf52f708372b7a24216fe18e341 100644 (file)
@@ -27,7 +27,6 @@
 #include <public/xen.h>
 #include <asm/hvm/hvm.h>
 
-#ifdef CONFIG_SMP
 static atomic_t waiting_for_crash_ipi;
 
 static int crash_nmi_callback(struct cpu_user_regs *regs, int cpu)
@@ -71,9 +70,7 @@ static void nmi_shootdown_cpus(void)
     atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1);
     /* Would it be better to replace the trap vector here? */
     set_nmi_callback(crash_nmi_callback);
-    /* Ensure the new callback function is set before sending
-     * out the NMI
-     */
+    /* Ensure the new callback function is set before sending out the NMI. */
     wmb();
 
     smp_send_nmi_allbutself();
@@ -88,7 +85,6 @@ static void nmi_shootdown_cpus(void)
     /* Leave the nmi callback set */
     disable_local_APIC();
 }
-#endif
 
 static void crash_save_xen_notes(void)
 {
@@ -102,16 +98,12 @@ static void crash_save_xen_notes(void)
 
 void machine_crash_shutdown(void)
 {
-    printk("machine_crash_shutdown: %d\n", smp_processor_id());
     local_irq_disable();
 
-#ifdef CONFIG_SMP
     nmi_shootdown_cpus();
-#endif
 
-#ifdef CONFIG_X86_IO_APIC
     disable_IO_APIC();
-#endif
+
     hvm_disable();
 
     crash_save_xen_notes();
index 391a50eb05c7196b4997ec213b7cf73fc31ce636..8d9f6f9e08724495950fd75f30c7327c0a48a4ba 100644 (file)
@@ -305,6 +305,9 @@ void __init __start_xen(multiboot_info_t *mbi)
         .stop_bits = 1
     };
 
+    extern void early_page_fault(void);
+    set_intr_gate(TRAP_page_fault, &early_page_fault);
+
     /* Parse the command-line options. */
     if ( (mbi->flags & MBI_CMDLINE) && (mbi->cmdline != 0) )
         cmdline = __va(mbi->cmdline);
@@ -501,21 +504,19 @@ void __init __start_xen(multiboot_info_t *mbi)
         kdump_start >>= PAGE_SHIFT;
         kdump_size >>= PAGE_SHIFT;
 
-        /* allocate pages for Kdump memory area */
+        /* Allocate pages for Kdump memory area. */
 
         k = alloc_boot_pages_at(kdump_size, kdump_start);
-
         if ( k != kdump_start )
             panic("Unable to reserve Kdump memory\n");
 
-        /* allocate pages for relocated initial images */
+        /* Allocate pages for relocated initial images. */
 
         k = ((initial_images_end - initial_images_start) & ~PAGE_MASK) ? 1 : 0;
         k += (initial_images_end - initial_images_start) >> PAGE_SHIFT;
 
         k = alloc_boot_pages(k, 1);
-
-        if ( !k )
+        if ( k == 0 )
             panic("Unable to allocate initial images memory\n");
 
         move_memory(k << PAGE_SHIFT, initial_images_start, initial_images_end);
index 3e6ab2856dda7dd90018c03dfd9d9da4640afc20..11960e56fb79341449587bb617e346b283793b6b 100644 (file)
@@ -935,6 +935,37 @@ asmlinkage int do_page_fault(struct cpu_user_regs *regs)
     return 0;
 }
 
+/*
+ * Early handler to deal with spurious page faults. For example, consider a 
+ * routine that uses a mapping immediately after installing it (making it 
+ * present). The CPU may speculatively execute the memory access before 
+ * executing the PTE write. The instruction will then be marked to cause a 
+ * page fault when it is retired, despite the fact that the PTE is present and 
+ * correct at that point in time.
+ */
+asmlinkage int do_early_page_fault(struct cpu_user_regs *regs)
+{
+    static int stuck;
+    static unsigned long prev_eip, prev_cr2;
+    unsigned long cr2 = read_cr2();
+
+    BUG_ON(smp_processor_id() != 0);
+
+    if ( (regs->eip != prev_eip) || (cr2 != prev_cr2) )
+    {
+        prev_eip = regs->eip;
+        prev_cr2 = cr2;
+        stuck    = 0;
+        return EXCRET_not_a_fault;
+    }
+
+    if ( stuck++ == 1000 )
+        panic("Early fatal page fault at %04x:%p (cr2=%p, ec=%04x)\n", 
+              regs->cs, _p(regs->eip), _p(cr2), regs->error_code);
+
+    return EXCRET_not_a_fault;
+}
+
 long do_fpu_taskswitch(int set)
 {
     struct vcpu *v = current;
index 2b760ce704606aa252bfd1886d638562e33cbeb6..93cd2379a78942f0af2d9a0d7f05bc96b80404de 100644 (file)
@@ -252,29 +252,3 @@ void unmap_domain_page_global(void *va)
     idx = (__va - IOREMAP_VIRT_START) >> PAGE_SHIFT;
     set_bit(idx, garbage);
 }
-
-paddr_t maddr_from_mapped_domain_page(void *va) 
-{
-    unsigned long __va = (unsigned long)va;
-    l2_pgentry_t *pl2e;
-    l1_pgentry_t *pl1e;
-    unsigned int idx;
-    struct mapcache *cache;
-    unsigned long mfn;
-
-    if ( (__va >= MAPCACHE_VIRT_START) && (__va < MAPCACHE_VIRT_END) )
-    {
-        cache = &mapcache_current_vcpu()->domain->arch.mapcache;
-        idx = ((unsigned long)va - MAPCACHE_VIRT_START) >> PAGE_SHIFT;
-        mfn = l1e_get_pfn(cache->l1tab[idx]);
-    }
-    else
-    {
-        ASSERT(__va >= IOREMAP_VIRT_START);
-        pl2e = virt_to_xen_l2e(__va);
-        pl1e = l2e_to_l1e(*pl2e) + l1_table_offset(__va);
-        mfn = l1e_get_pfn(*pl1e);
-    }
-    
-    return ((paddr_t)mfn << PAGE_SHIFT) | ((unsigned long)va & ~PAGE_MASK);
-}
index 566f4d42790e972e41d78b267f7526c286e9d5a5..454e963fe3c486033b5db2419089e5292ee45a4c 100644 (file)
@@ -536,6 +536,14 @@ ENTRY(spurious_interrupt_bug)
         pushl $TRAP_spurious_int<<16
         jmp   handle_exception
 
+ENTRY(early_page_fault)
+        SAVE_ALL_NOSEGREGS(a)
+        movl  %esp,%edx
+        pushl %edx
+        call  do_early_page_fault
+        addl  $4,%esp
+        jmp   restore_all_xen
+
 ENTRY(nmi)
 #ifdef CONFIG_X86_SUPERVISOR_MODE_KERNEL
         # NMI entry protocol is incompatible with guest kernel in ring 0.
index 87602a3d86dca9c808f251b094f5746e54daafeb..b28b644c336a1f3682a013c48a613d09153fea10 100644 (file)
@@ -478,6 +478,12 @@ ENTRY(double_fault)
         call  do_double_fault
         ud2
 
+ENTRY(early_page_fault)
+        SAVE_ALL
+        movq  %rsp,%rdi
+        call  do_early_page_fault
+        jmp   restore_all_xen
+
 ENTRY(nmi)
         pushq $0
         SAVE_ALL
index 3f83b2a6db0ab4c0c26ccdcf3183743ff7bd6eb6..7067f33ff796e0473df63313f516702a353a4906 100644 (file)
@@ -34,13 +34,6 @@ void unmap_domain_page(void *va);
 void *map_domain_page_global(unsigned long mfn);
 void unmap_domain_page_global(void *va);
 
-/* 
- * Convert a VA (within a page previously mapped in the context of the
- * currently-executing VCPU via a call to map_domain_page(), or via a
- * previous call to map_domain_page_global()) to the mapped machine address.
- */
-paddr_t maddr_from_mapped_domain_page(void *va);
-
 #define DMCACHE_ENTRY_VALID 1U
 #define DMCACHE_ENTRY_HELD  2U
 
@@ -109,8 +102,6 @@ domain_mmap_cache_destroy(struct domain_mmap_cache *cache)
 #define map_domain_page_global(mfn)         maddr_to_virt((mfn)<<PAGE_SHIFT)
 #define unmap_domain_page_global(va)        ((void)(va))
 
-#define maddr_from_mapped_domain_page(va)   (virt_to_maddr(va))
-
 struct domain_mmap_cache { 
 };